<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Pgwatch2 :: DBs to monitor</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li><a href="/index"><h4>PgWatch2</h4></a></li>
        <li><a href="https://www.cybertec-postgresql.com/en/"><img src="/static/logo.png" alt="Cybertec" height="35px"></a></li>
      </ul>
      <ul class="nav navbar-nav navbar-right">
        <li class="active"><a href="/dbs">DBs<span class="sr-only"></span></a></li>
        <li><a href="#">|</a></li>
        <li><a href="/metrics">Metrics</a></li>
        {% if not no_component_logs %}
        <li><a href="#">|</a></li>
        <li class="dropdown" title="Logs will open in a new window">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Logs<span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="/logs/pgwatch2/200" target="_blank">Pgwatch2 [last 200 lines]</a></li>
            <li><a href="/logs/influxdb/200" target="_blank">InfluxDB [last 200 lines]</a></li>
            <li><a href="/logs/grafana/200" target="_blank">Grafana [last 200 lines]</a></li>
            <li><a href="/logs/postgres/200" target="_blank">Postgres [last 200 lines]</a></li>
            <li><a href="/logs/webui/200" target="_blank">Web UI [last 200 lines]</a></li>
            <li><a href="/versions" target="_blank">Component versions</a></li>
          </ul>
        </li>
        {% endif %}
        {% if no_anonymous_access and session['logged_in'] %}
        <li><a href="#">|</a></li>
        <li><a href="/logout">Log out</a></li>
        {% endif %}
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

<div class="container-fluid">

<div class="row" style="padding-left: 10px">

{% if messages %}
    {% for message in messages: %}
    <div class="alert alert-warning alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      {{message}}
    </div>
    {% endfor %}
{% endif %}

<h3>Databases under monitoring</h3>

<div class="table-responsive">
    <table class="table table-striped">
        <thead>
            <tr>
                <td>ID</td>
                <td title="NB! Choose a good name as this shouldn't be changed later (cannot easily update InfluxDB data). Will be used as prefix during DB discovery mode">Unique name</td>
                <td title="NB! For 'pgbouncer' insert the 'to be monitored' pool name to 'dbname' field. For dbtype='pg-continuous-discovery' one can also specify regex inclusion/exclusion patterns">DB type</td>
                <td>DB host</td>
                <td>DB port</td>
                <td title="NB! If left empty all DBs from the cluster will be added, prefixed with the 'Unique name'">DB dbname <span class="glyphicon glyphicon-info-sign" title="NB! If left empty for 'postgres', all DBs from the cluster will be added, prefixed with the 'Unique name'"></span></td>
                <td title="POSIX regex input. Relevant only for dbtype=pg-continuous-discovery">DB name inclusion pattern<span class="glyphicon glyphicon-info-sign" title="POSIX regex input. Relevant only for dbtype=pg-continuous-discovery"></span></td>
                <td title="POSIX regex input. Relevant only for dbtype=pg-continuous-discovery">DB name exclusion pattern<span class="glyphicon glyphicon-info-sign" title="POSIX regex input. Relevant only for dbtype=pg-continuous-discovery"></span></td>
                <td>DB user</td>
                <td title="NB! Password is stored in plain-text in the database">DB password</td>
                <td title="NB! If checked pgwatch daemon will automatically try to create the CPU load monitoring and stat_statements helper">Is superuser?</td>
                <td title="libpq 'sslmode' parameter. If 'require' or 'verify-full' then no metrics will be gathered if safe connection cannot be established">SSL Mode</td>
                <td title="Preset config OR custom config needs to be specified">Preset config</td>
                <td title='{"metric":interval_seconds,...}'>Custom config</td>
                <td title='User defined tags for extra meaning in InfluxDB e.g. {"env": "prod", "app": "xyz"}'>Custom tags</td>
                <td title='In seconds. Should stay low for critical DBs'>Statement timeout [seconds]</td>
                <td>Last modified</td>
                <td title="A tip - uncheck when leaving 'dbname' empty to review all found DBs before activation">Enabled?</td>
                <td></td>
                <td></td>
            </tr>
        </thead>
        <tbody>
            {% for row in data: %}
            <tr>
                <form action="/dbs" method="post">
                    <td>{{row['md_id']}}<input type="hidden" name="md_id" value="{{row['md_id']}}"></td>
                    <td><input type="hidden" name="md_unique_name" value="{{row['md_unique_name']|e}}" size="8">{{row['md_unique_name']|e}}</td>
                    <td>
                        <select name="md_dbtype">
                            <option value="postgres" {% if row['md_dbtype'] == "postgres" %}selected{% endif %}>postgres</option>
                            <option value="pgbouncer"{% if row['md_dbtype'] == "pgbouncer" %}selected{% endif %}>pgbouncer</option>
                            <option value="postgres-continuous-discovery"{% if row['md_dbtype'] == "postgres-continuous-discovery" %}selected{% endif %}>pg-continuous-discovery</option>
                        </select>
                    </td>
                    <td><input type="text" name="md_hostname" value="{{row['md_hostname']|e}}" size="10"></td>
                    <td><input type="text" name="md_port" value="{{row['md_port']|e}}" size="5"></td>
                    <td><input type="text" name="md_dbname" value="{{row['md_dbname']|e}}" size="10"></td>
                    <td><input type="text" name="md_include_pattern" value="{{row['md_include_pattern']|e}}" size="6"></td>
                    <td><input type="text" name="md_exclude_pattern" value="{{row['md_exclude_pattern']|e}}" size="6"></td>
                    <td><input type="text" name="md_user" value="{{row['md_user']|e}}" size="8"></td>
                    <td><input type="password" name="md_password" value="***" size="6" title="if left to default ***, password will not be changed"></td>
                    <td><input type="checkbox" name="md_is_superuser" {% if row['md_is_superuser'] %}checked{% endif %}></td>
                    <td>
                        <select name="md_sslmode">
                            <option value="disable" {% if row['md_sslmode'] == "disable" %}selected{% endif %}>disable</option>
                            <option value="require"{% if row['md_sslmode'] == "require" %}selected{% endif %}>require</option>
                            <option value="verify-full"{% if row['md_sslmode'] == "verify-full" %}selected{% endif %}>verify-full</option>
                        </select>
                    </td>
                    <td>
                        <select name="md_preset_config_name">
                            <option value="" title="Empty. 'Custom config' must be filled" ></option>
                            {% for pc in preset_configs %}
                            <option value="{{pc['pc_name']|e}}" {% if pc['pc_name'] == row['md_preset_config_name'] %}selected{% endif %}>{{pc['pc_name']|e}}</option>
                            {% endfor %}
                        </select>
                        <br />
                        <a class="show_metrics" href="/metrics" title="Show preset configs and metric definitions in a new window" target="_blank">show</a>&nbsp;|&nbsp;
                        <a class="copy_to_custom" href="" title="Copy JSON to 'Custom config' for editing">copy</a>
                    </td>
                    <td title='{"metric":interval,...}'><textarea name="md_config" cols="8">{% if row['md_config'] %} {{row['md_config']}} {% endif %}</textarea></td>
                    <td title='{"env": "prod", ...}'><textarea name="md_custom_tags" cols="8">{% if row['md_custom_tags'] %} {{row['md_custom_tags']}} {% endif %}</textarea></td>
                    <td><input type="text" name="md_statement_timeout_seconds" value="{{row['md_statement_timeout_seconds']}}" size="2"></td>
                    <td>{{row['md_last_modified_on']}}</td>
                    <td><input type="checkbox" name="md_is_enabled" {% if row['md_is_enabled'] %}checked{% endif %}></td>
                    <td><input type="submit" class="save" name="save" value="Save"></td>
                    <td><input type="submit" class="delete" name="delete" value="Delete"></td>
                </form>
            </tr>
            {% endfor %}
            <tr>
                <form action="/dbs" method="post">
                    <td></td>
                    <td><input type="text" name="md_unique_name" value="" size="8" title="NB! Choose a good name as this shouldn't be changed later (cannot easily update InfluxDB data)"></td>
                    <td>
                        <select name="md_dbtype" id="md_dbtype" title="'postgres': Single Postgres DB monitoring, 'pgbouncer': PgBouncer traffic stats for a single pool, 'pg-continuous-discovery': Specified PG cluster will be polled for new DBs to be monitored periodically (with optional pattern matching)">
                            <option value="postgres">postgres</option>
                            <option value="pgbouncer">pgbouncer</option>
                            <option value="postgres-continuous-discovery">pg-continuous-discovery</option>
                        </select>
                    </td>
                    <td><input type="text" name="md_hostname" value="" size="10"></td>
                    <td><input type="text" name="md_port" value="5432" size="5"></td>
                    <td><input type="text" name="md_dbname" value="" size="10"></td>
                    <td><input type="text" name="md_include_pattern" value="" size="6"></td>
                    <td><input type="text" name="md_exclude_pattern" value="" size="6"></td>
                    <td><input type="text" name="md_user" value="" size="8"></td>
                    <td><input type="password" name="md_password" value="" size="6"></td>
                    <td><input type="checkbox" name="md_is_superuser"></td>
                    <td>
                        <select name="md_sslmode">
                            <option value="disable">disable</option>
                            <option value="require">require</option>
                            <option value="verify-full">verify-full</option>
                        </select>
                    </td>
                    <td>
                        <select name="md_preset_config_name" id="md_preset_config_name">
                            <option value="" title="Empty. 'Custom config' must be filled" ></option>
                            {% for pc in preset_configs %}
                            <option value="{{pc['pc_name']|e}}">{{pc['pc_name']|e}}</option>
                            {% endfor %}
                        </select>
                        <br />
                        <a class="show_metrics" href="/metrics" title="Show JSON config in a new window" target="_blank">show</a>&nbsp;|&nbsp;
                        <a class="copy_to_custom" href="" title="Copy JSON to 'Custom config' for editing">copy</a>
                    </td>
                    <td title='{"metric":interval,...}'><textarea name="md_config" id="md_config" value="" cols="8"></textarea></td>
                    <td title='{"env": "prod", ...}'><textarea name="md_custom_tags" id="md_custom_tags" value="" cols="8"></textarea></td>
                    <td><input type="text" name="md_statement_timeout_seconds" size="2" value="5"></td>
                    <td></td>
                    <td><input type="checkbox" name="md_is_enabled" checked></td>
                    <td><input type="submit" class="new" name="new" value="New"></td>
                    <td></td>
                </form>
            </tr>
        </tbody>
    </table>
</div>  <!-- table -->
</div>  <!-- row -->

<div class="row" style="padding-left: 10px">
    <h3>Active metrics listing</h3>
    <ul>
    {% for m in metrics_list: %}
        <li style="display: inline"><b>{{m['m_name']}}</b> [ver: {{m['versions']}}]</li>
    {% endfor %}

    </ul>
</div>

<div class="row" style="padding-left: 10px">
    <h3>InfluxDB metrics data cleanup</h3>
    <br />
    <p>Nr. of unique hosts found from Influx: {{influx_active_dbnames|length}}</p>
    <form action="/dbs" method="post">
        <span style="font-weight: bold">DB "Unique name"</span> (NB! It could take up to 3min for background gatherers to stop so no point to click directly after removing a host from monitoring):
        <br />
        <input type="text" name="influx_single_unique_name" id="influx_single_unique_name" list="influx_active_dbnames" autocomplete="off" title="Start typing to get autocomplete">
        <br />
        <input type="submit" id="influx_delete_single" name="influx_delete_single" value="Delete single DB metrics">
        <br />
        <br />
        <input type="submit" id="influx_delete_all" name="influx_delete_all" value="Delete all metrics for all non-active DBs">
        <br />
        <br />
        <br />
    </form>

    <datalist id="influx_active_dbnames">
      {% for db in influx_active_dbnames: %}
      <option value="{{db}}">
      {% endfor %}
    </datalist>
</div>

</div>  <!-- container -->

<script src="/static/jquery-3.1.1.min.js"></script>
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>

<script>
    var preset_configs = {{preset_configs_json}};

    $(document).ready(function(){
        $(".copy_to_custom").click(function(event){
            event.preventDefault();

            var preset_config_json = preset_configs[$(this).parent().find("[name='md_preset_config_name']").val()];
            // alert(preset_config_json);
            $(this).parent().parent().find("[name='md_config']").val(preset_config_json);
            $(this).parent().find("select").val("");
            return false;
        });

        $(".show_metrics").click(function(event){
            $(this).attr('href', $(this).attr('href') + '#' + $(this).parent().find("select").val());
        });

        $(".delete").click(function(event){
            return confirm('Remove DB "' + $(this).parent().parent().find("[name='md_unique_name']").val() + '" from monitoring? NB! This does not remove gathered metrics data from InfluxDB, see bottom of page for that')
        });

        $("#influx_delete_all").click(function(event){
            return confirm('Are you sure you want to delete all gathered metrics data for non-active DB-s?')
        });

        $("#influx_delete_single").click(function(event){
            if ($("#influx_single_unique_name").val().trim() == '') {
                alert("Unique name empty!");
                return false;
            }
            return confirm('Are you sure you want to delete all gathered metrics for DB: "' + $("#influx_single_unique_name").val() + '" ?')
        });

        $(".save").add('.new').click(function(event){
            if ($(this).parent().parent().find("[name='md_unique_name']").val() == null || !($(this).parent().parent().find("[name='md_unique_name']").val().trim() > '')) {
                alert("'Unique name' cannot be empty");
                return false;
            }
            if ($(this).parent().parent().find("[name='md_hostname']").val() == null || !($(this).parent().parent().find("[name='md_hostname']").val().trim() > '')) {
                alert("'DB host' cannot be empty");
                return false;
            }
            if ($(this).parent().parent().find("[name='md_port']").val() == null || !($(this).parent().parent().find("[name='md_port']").val().trim() > '')) {
                alert("'DB port' cannot be empty");
                return false;
            }
            if ($(this).parent().parent().find("[name='md_user']").val() == null || !($(this).parent().parent().find("[name='md_user']").val().trim() > '')) {
                alert("'DB user' cannot be empty");
                return false;
            }

            var custom_config = $(this).parent().parent().find("[name='md_config']").val();
            var preset_config = $(this).parent().parent().find("[name='md_preset_config_name']").val();
            if (custom_config.trim() == '' && preset_config == '') {
                alert('Preset OR custom config needs to be specifief!');
                return false;
            }

            // check influx identifier policies - only ascii, digits (not as 1st char) and underscores
            var db_unique = $(this).parent().parent().find("[name='md_unique_name']").val()
            if (db_unique[0].match(/\d/)) {
                alert("'Unique name' can only start with a letter or underscore");
                return false;
            }
            if (db_unique.match(/[^\d\w_]/)) {
                alert("'Unique name' can only contain letters, digits and underscores");
                return false;
            }

        });

        $("#md_dbtype").change(function(event){
            if ($(this).val() == 'pgbouncer') {
                $("#md_preset_config_name").val('pgbouncer');
                alert('NB! Preset Config set to "pgbouncer"');
            } else if ($(this).val() == 'postgres' || $(this).val() == 'postgres-continuous-discovery') {
                $("#md_preset_config_name").val('');
            }
        });
    });
</script>
</body>
</html>
